`include "md5round.v"
`include "defs.v"

module md5 (
    input clk,
    input rst,
    input [127:0]in,
    input in_valid,

    output reg [127:0]out,
    output reg out_valid,
    output reg ready
);
    reg [31:0] A;
    reg [31:0] B;
    reg [31:0] C;
    reg [31:0] D;
    reg [31:0] AA;
    reg [31:0] BB;
    reg [31:0] CC;
    reg [31:0] DD;
    reg [31:0] next_A;
    reg [31:0] next_B;
    reg [31:0] next_C;
    reg [31:0] next_D;

    reg [3:0] phase;
    reg [7:0] state;
    reg [7:0] next_state;

    reg [511:0] msg;
    reg out_r;

    always@(posedge clk) begin
        if(rst) begin
            A <= `A_INIT;
            B <= `B_INIT;
            C <= `C_INIT;
            D <= `D_INIT;
            state <= (1 << `idle);
            AA <= 0;
            BB <= 0;
            CC <= 0;
            DD <= 0;
            phase <= 0;
            msg <= 0;
            out_r <= 0;
        end else begin
            out_r <= state[`finished];
            state <= next_state;
            if (next_state[`idle]) begin
                AA <= 0;
                BB <= 0;
                CC <= 0;
                DD <= 0;
            end else if(next_state[`r0] && state[`idle]) begin
                AA <= A;
                BB <= B;
                CC <= C;
                DD <= D;
            end

            // TODO: add code for update A B C D

            // TODO: add code for update phase

            if (next_state[`idle]) begin
                msg <= 0;
            end else if (next_state[`r0] && state[`idle]) begin
                msg <= {in, in, in, in};
            end
        end
    end

    always@(*) begin
        next_A = A;
        next_B = B;
        next_C = C;
        next_D = D;
        next_state = state;
        out_valid = out_r;
        ready = state[`idle];
        out = {A, B, C, D};
        
        // TODO: add code for the starting of the state machine

        // TODO: add code for 4 rounds calc, you must use md5round module
        
        if (state[`finished]) begin
            // TODO: according to c code, add the final accumulate step
            next_state = (1 << `turn_arnd);
        end

        if(state[`turn_arnd]) begin
            next_state = (1 << `idle);
        end
    end
endmodule